const LazyLoad = {
  // install方法
  install(Vue, options) {
    const defaultSrc = options.default;
    Vue.directive("lazy", {
      bind(el, binding) {
        LazyLoad.init(el, binding.value, defaultSrc);
      },
      inserted(el) {
        if (IntersectionObserver) {
          LazyLoad.observe(el);
        } else {
          LazyLoad.listenerScroll(el);
        }
      },
    });
  },
  // 初始化
  init(el, val, def) {
    el.setAttribute("data-src", val);
    el.setAttribute("src", def);
  },
  // 利用IntersectionObserver监听el
  observe(el) {
    var io = new IntersectionObserver((entries) => {
      // entries为一个数组包含所有被观察的对象
      for (let i of entries) {
        // isIntersecting的值为布尔值, 戴代表是否处于观测区域, 当处于观测区域重新设置url
        if (i.isIntersecting) {
          let img = i.target;
          let trueSrc = img.getAttribute("data-src");
          // 所有以data开头的自定义属性都会存储在标签元素的dataset对象当中, 可以通过data后面的名字访问, 如data-src
          // let trueSrc = el.dataset.src;
          img.setAttribute("src", trueSrc);
          // 加载完成结束观测(交叉监听)
          io.unobserve(img);
        }
      }
    });
    // 给所有使用自定义指令的图片添加交叉监听
    io.observe(el);
  },
  // 监听scroll事件
  listenerScroll(el) {
    const handler = LazyLoad.throttle(LazyLoad.load, 200);
    LazyLoad.load(el);
    window.addEventListener("scroll", () => {
      handler(el);
    });
  },
  // 加载真实图片
  load(el) {
    const windowHeight = document.documentElement.clientHeight;
    const elTop = el.getBoundingClientRect().top;
    const elBtm = el.getBoundingClientRect().bottom;
    const realSrc = el.dataset.src;
    // 保证在页面当中
    if (elTop - windowHeight < 0 && elBtm > 0) {
      if (realSrc) {
        el.src = realSrc;
        // 移除之后下次不会触发
        el.removeAttribute("data-src");
      }
    }
  },
  // 节流
  throttle(fn, delay) {
    // console.log(1);
    let timer;
    let prevTime;
    // 此处是handler函数
    // 此处的参数是触发事件的元素本身, 一次只传入一个
    return function (...args) {
      //   console.log(args);
      const currTime = Date.now();
      // 此处的this指向LazyLoad, 存储最外层对象好调用load方法
      const context = this;
      // 如果没有事件把当前的时间作为前一个时间,后面的以此为基准
      if (!prevTime) prevTime = currTime;
      console.log(prevTime, currTime);

      // 每次滚动都会触发handle函数, 需要清除前面开启的定时器
      clearTimeout(timer);

      // 当间隔大于设置的值时直接触发加载图片的函数load, 如果没有这部分则代表只会有最后一个定时器生效, 而且用户一直滚动定时器永远不会执行, 只会在结束后的规定时间间隔执行, 有了这部分就能保证不管用户怎么滑动,都能在函数触发的一定时间后调用, 并且调用后清除定时器, 直接返回, 后面的定时器也不会再执行
      if (currTime - prevTime > delay) {
        // 并且记录当前时间
        prevTime = currTime;
        fn.apply(context, args);
        // 清除定时器
        clearTimeout(timer);
        // 返回
        return;
      }

      // 如果没有定时器会出先图片一直是默认图片的情况直到下次触发滚动事件
      // 此处设置定时器保证只要触发了handle函数就能在一定时间直接加载
      timer = setTimeout(function () {
        // 如果上述条件不成立会在每隔一段时间重新设置新的起始时间
        // 从新设置前一个时间
        // console.log("定时器");
        prevTime = Date.now();
        // 清除定时器
        timer = null;
        // clearTimeout(timer);
        fn.apply(context, args);
      }, delay);
    };
  },
};

export default LazyLoad;
